package com.masonluo.mlonlinejudge.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.masonluo.mlonlinejudge.dao.*;
import com.masonluo.mlonlinejudge.entity.*;
import com.masonluo.mlonlinejudge.exceptions.ResourceExistException;
import com.masonluo.mlonlinejudge.exceptions.ResourceNotFoundException;
import com.masonluo.mlonlinejudge.mapper.ExperimentMapper;
import com.masonluo.mlonlinejudge.mapper.ExperimentResultMapper;
import com.masonluo.mlonlinejudge.mapper.ProblemMapper;
import com.masonluo.mlonlinejudge.mapper.UserMapper;
import com.masonluo.mlonlinejudge.model.bo.ExperimentBo;
import com.masonluo.mlonlinejudge.model.dto.ExperimentScoreResultDto;
import com.masonluo.mlonlinejudge.model.dto.ExperimentUploadDto;
import com.masonluo.mlonlinejudge.model.param.ExperimentParam;
import com.masonluo.mlonlinejudge.model.param.ExperimentUploadParam;
import com.masonluo.mlonlinejudge.model.param.ProblemParam;
import com.masonluo.mlonlinejudge.model.vo.ExperimentIdAndNameVo;
import com.masonluo.mlonlinejudge.model.vo.ExperimentVo;
import com.masonluo.mlonlinejudge.service.*;
import com.masonluo.mlonlinejudge.utils.CollectionUtils;
import com.masonluo.mlonlinejudge.utils.DateTimeUtils;
import lombok.SneakyThrows;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.SocketUtils;

import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: mloj-backend
 * @description:
 * @author: LOTP
 * @create: 2021-10-06 01:55
 **/
@Service
public class ExperimentServiceImpl implements ExperimentService {

    @Autowired
    private ExperimentRepository experimentRepository;
    @Autowired
    private ExperimentProblemRepository experimentProblemRepository;
    @Autowired
    private ExperimentSchoolRepository experimentSchoolRepository;
    @Autowired
    private ExperimentClassRepository experimentClassRepository;
    @Autowired
    private ExperimentMapper experimentMapper;
    @Autowired
    private ProblemMapper problemMapper;
    @Autowired
    private ProblemService problemService;
    @Autowired
    private IoSampleService ioSampleService;
    @Autowired
    private SchoolService schoolService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserInfoRepository userInfoRepository;
    @Autowired
    private ExperimentResultRepository experimentResultRepository;
    @Autowired
    private ExperimentResultMapper experimentResultMapper;
    @Autowired
    private ExperimentResultService experimentResultService;
    @Autowired
    private SolutionService solutionService;

    private static final int _1MB = 1024 * 1024;



    public List<ProblemParam> findProblemByExperimentId(Integer experimentId, String category){
        List<ProblemParam> problems = experimentProblemRepository.findProblemByExperimentId(experimentId, category);
        problems.forEach(problemParam -> {
            problemParam.setTags(problemService.findTagVoByProblemId(problemParam.getId()));
            problemParam.setMemoryLimit(problemParam.getMemoryLimit()/_1MB);
            problemParam.setIoSamples(ioSampleService.findByProblemId(problemParam.getId()));
        });
        return problems;
    }

    @Override
    public boolean exist(Integer id) {
        return  experimentRepository.countById(id) > 0;
    }

    @Override
    public ExperimentVo findById(Integer id) {
        Experiment experiment = experimentRepository.selectById(id);
        if (experiment == null) {
            throw new ResourceExistException(String.format("当前实验不存在"));
        }
        ExperimentVo experimentVo = experimentMapper.doToVo(experiment);
        List<ProblemParam> optionalProblems = findProblemByExperimentId(experimentVo.getId(),  "OPTIONAL");
        List<ProblemParam> requiredProblems = findProblemByExperimentId(experimentVo.getId(),  "REQUIRED");
        experimentVo.setOptionalQuestions(optionalProblems);
        experimentVo.setRequiredQuestions(requiredProblems);
        int creatorId = Integer.parseInt(experimentVo.getCreator());
        experimentVo.setCreator(userService.findUsernameById(creatorId));
        experimentVo.setCreatorSchool(userService.findUserSchoolById(creatorId));
        return  experimentVo;

    }

    @Override
    public List<ExperimentIdAndNameVo> findExperimentIdAndNameBySchoolIdAndStatus(Integer schoolId,String status){
        return experimentSchoolRepository.findExperimentIdAndNameBySchoolIdAndStatus(schoolId, status);
    }



    @Override
    public ExperimentBo findByExperimentIdAndSchoolId(Integer experimentId, Integer schoolId) {
        ExperimentBo experimentBo = experimentRepository.findByExperimentIdAndSchoolId(experimentId, schoolId);
        experimentBo.setLimitDateTime(experimentBo.getStartTime(), experimentBo.getEndTime());
        List<ProblemParam> optionalProblems = findProblemBySchoolId(experimentBo.getId(), schoolId, "OPTIONAL");
        List<ProblemParam> requiredProblems = findProblemBySchoolId(experimentBo.getId(), schoolId, "REQUIRED");
        experimentBo.setOptionalQuestions(optionalProblems);
        experimentBo.setRequiredQuestions(requiredProblems);
        //experimentBo.setSchoolId(schoolId);
        return experimentBo;
    }

    @Override
    public ExperimentBo findByExperimentIdAndUserId(Integer experimentId, Integer userId) {
        UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
        Integer schoolId = userInfo.getSchoolId();
        ExperimentBo experimentBo = experimentRepository.findByExperimentIdAndSchoolId(experimentId, schoolId);
        experimentBo.setLimitDateTime(experimentBo.getStartTime(), experimentBo.getEndTime());
        List<ProblemParam> optionalProblems = findProblemByExperimentId(experimentBo.getId(), "OPTIONAL");
        List<ProblemParam> requiredProblems = findProblemByExperimentId(experimentBo.getId(), "REQUIRED");

        optionalProblems.forEach(optionalProblem->{
            boolean successStatus = solutionService.judgeSuccessByProblemIDAndUserId(experimentId, optionalProblem.getId(), userId);
            boolean doneStatus = solutionService.judgeDoneByProblemIDAndUserId(experimentId, optionalProblem.getId(), userId);
            if (doneStatus){
                optionalProblem.setStatus("NeverDo");
            }else {
                if (successStatus){
                    optionalProblem.setStatus("PASS");
                }else {
                    optionalProblem.setStatus("FAIL");
                }
            }
        });

        requiredProblems.forEach(requiredProblem->{
            boolean successStatus = solutionService.judgeSuccessByProblemIDAndUserId(experimentId, requiredProblem.getId(), userId);
            boolean doneStatus = solutionService.judgeDoneByProblemIDAndUserId(experimentId, requiredProblem.getId(), userId);
            if (doneStatus){
                requiredProblem.setStatus("NeverDo");
            }else {
                if (successStatus){
                    requiredProblem.setStatus("PASS");
                }else {
                    requiredProblem.setStatus("FAIL");

                }
            }
        });

        experimentBo.setOptionalQuestions(optionalProblems);
        experimentBo.setRequiredQuestions(requiredProblems);
        //experimentBo.setSchoolId(schoolId);
        return experimentBo;
    }



    /*@Override
    public ExperimentVo findById(Integer id) {
        Experiment experiment = experimentRepository.selectById(id);
        if (experiment == null) {
            throw new ResourceExistException(String.format("The experiment [%d] does not exist", id));
        }
        ExperimentVo experimentVo = experimentMapper.doToVo(experiment);
        //experimentBo.setLimitDateTime(DateTimeUtils.dateToString(experiment.getStartTime()),DateTimeUtils.dateToString(experiment.getEndTime()));
//        List<Integer> problemIdsByExperimentId = experimentProblemRepository.findProblemIdsByExperimentId(id);
//        experimentVo.setQuestions(problemService.listByIds(problemIdsByExperimentId));

        experimentVo.setQuestions(findProblemByExperimentId(id));
        return experimentVo;
    }*/

    @Override
    public List<Experiment> listByIds(List<Integer> ids) {
        if (ObjectUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<Experiment> experiments = experimentRepository.listByIds(ids);
        return experiments;
    }

    @Override
    public <T> List<T> list(Integer pageNum, Integer pageSize, Integer userId, String status) {
        IPage<Experiment> page = new Page<>(pageNum, pageSize);
        /*QueryWrapper<Experiment> queryWrapper = new QueryWrapper<>();
        queryWrapper.ne("status",status);
        queryWrapper.orderByAsc("weight");*/
        if (Objects.isNull(userId)){
            if ((pageNum - 1) * pageSize > countAll()) {
                throw new ResourceNotFoundException(String.format("The pageNum [%d] does not exist.", pageNum));
            }
            List<Experiment> experiments = experimentRepository.listAll(pageNum, pageSize);
            List<ExperimentVo> experimentVos = experimentMapper.doToVo(experiments);
            experimentVos.forEach(experimentVo->{
               /* List<ProblemParam> optionalProblems = findProblemByExperimentId(experimentVo.getId(),  "OPTIONAL");
                List<ProblemParam> requiredProblems = findProblemByExperimentId(experimentVo.getId(),  "REQUIRED");
                experimentVo.setOptionalQuestions(optionalProblems);
                experimentVo.setRequiredQuestions(requiredProblems);*/
                int creatorId = Integer.parseInt(experimentVo.getCreator());
                experimentVo.setCreator(userService.findUsernameById(creatorId));
                experimentVo.setCreatorSchool(userService.findUserSchoolById(creatorId));
            });
            return (List<T>) experimentVos;
        }


        String role = userService.getUserRolesByUserId(userId);
        if ("superAdmin".equals(role)){
            IPage<Experiment> experimentIPage = experimentRepository.selectPage(page, null);
            List<ExperimentVo> experiments = new ArrayList<>();
            if (!CollectionUtils.isEmpty(experimentIPage.getRecords())){
                experiments = (List<ExperimentVo>) page.getRecords().stream().map(experiment -> {
                    return experimentMapper.doToVo(experiment);
                }).collect(Collectors.toList());
            }
            for (ExperimentVo experimentVo:experiments){
                /*List<ProblemParam> optionalProblems = findProblemByExperimentId(experimentVo.getId(),  "OPTIONAL");
                List<ProblemParam> requiredProblems = findProblemByExperimentId(experimentVo.getId(),  "REQUIRED");
                experimentVo.setOptionalQuestions(optionalProblems);
                experimentVo.setRequiredQuestions(requiredProblems);*/
                //List<Integer> schoolIds = experimentSchoolRepository.findSchoolIdsByExperimentId(experimentVo.getId());
                //experimentVo.setSchoolIds(schoolIds);
                List<String> schoolNames = experimentSchoolRepository.findSchoolNamesByExperimentId(experimentVo.getId());
                experimentVo.setSchoolNames(schoolNames);
                int creatorId = Integer.parseInt(experimentVo.getCreator());
                experimentVo.setCreator(userService.findUsernameById(creatorId));
                experimentVo.setCreatorSchool(userService.findUserSchoolById(creatorId));
                experimentVo.setExperimentProblemResults(experimentResultService.findExperimentProblemResult(userId,experimentVo.getId()));
            }
            return (List<T>) experiments;
        }else if ("schoolAdmin".equals(role)) {
            UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
            List<ExperimentBo> experimentBos = listBySchoolId(userInfo.getSchoolId(),userId,status,pageNum,pageSize);
            return (List<T>) experimentBos;
            //return (List<T>) listBySchoolId(userInfo.getSchoolId(),status,pageNum,pageSize);

        }else if ("teacher".equals(role)){
            UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
            List<ExperimentBo> experimentBos = listBySchoolId(userInfo.getSchoolId(),userId,status,pageNum,pageSize);
            return (List<T>) experimentBos;

        }else if ("student".equals(role)){
            UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);

            List<ExperimentBo> experimentBos = listBySchoolId(userInfo.getSchoolId(), userId, status, pageNum, pageSize);
            return (List<T>) experimentBos;
        }else {
            throw new ResourceNotFoundException(String.format("该用户未赋予角色或赋予的角色不存在"));
        }

    }

    /**
    * @Description: 管理员修改实验
    */
    @SneakyThrows
    @Override
    public <T> T updateExperimentById(Integer userId, ExperimentParam experimentParam) {
        String role = userService.getUserRolesByUserId(userId);
        if (!"schoolAdmin".equals(role) && !"superAdmin".equals(role) && !"teacher".equals(role)){
            throw new ResourceExistException(String.format("您无权修改实验"));
        }
        Experiment experiment = experimentRepository.selectById(experimentParam.getId());
        if (experiment == null ) {
            throw new ResourceExistException(String.format("The experiment [%d] does not exist", experimentParam.getId()));
        }else {
            //将实验关联的信息更新
            //校管理员可以修改自己学校人员创建的实验
            //创建者可以对修改自己创建的实验
            //但无法直接对其他管理员创建的实验进行修改，所以这时候其修改实验的实质是增加一个实验
            UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
            Integer createSchoolId = userInfoRepository.getUserInfoByUserId(experiment.getCreatorId()).getSchoolId();
            if ("superAdmin".equals(role) || ("schoolAdmin".equals(role) && Objects.equals(createSchoolId,userInfo.getSchoolId())) || Objects.equals(userId, experiment.getCreatorId())){
                Experiment experiment1 = experimentMapper.experimentParamExperiment(experimentParam);
                experimentRepository.updateById(experiment1);

                //每次更新完实验信息后，都需要更新与之有关的表，比如实验成绩表

                Map map = new HashMap();
                map.put("experiment_id",experiment1.getId());
                List<ExperimentScoreResult> experimentScoreResults = experimentResultRepository.selectByMap(map);
                if (experimentScoreResults.size() != 0){
                    ExperimentScore experimentScore = ExperimentScore.toStrJson(experimentScoreResults.get(0).getExperimentScore()).get(0);
                    //如果更改了实验的名称
                    if (!Objects.equals(experiment1.getName(),experimentScore.getName())){
                        experimentScore.setName(experiment1.getName());
                        experimentScore.setPassNum(0);
                        experimentResultRepository.updateExperimentById(experiment1.getId(),ExperimentScore.toJsonStr(Collections.singletonList(experimentScore)));
                    }
                }

                List<Integer> newRequiredProblems = removeProblems(experimentParam,"REQUIRED");
                List<Integer> newOptionalProblems = removeProblems(experimentParam,"OPTIONAL");
                //删除完共同题目之后那么newProblems中剩下的就是新题目了
                if (newOptionalProblems.size() != 0){
                    doProblemRelatedExperiment(newOptionalProblems, "OPTIONAL",experiment1);
                }
                if (newRequiredProblems.size() != 0){
                    doProblemRelatedExperiment(newRequiredProblems, "REQUIRED",experiment1);
                }
                return (T) findById(experimentParam.getId());


            }else {
                if (!"ENABLE".equals(experimentParam.getStatus()) && !"DISABLE".equals(experimentParam.getStatus())){
                    throw new IllegalArgumentException("请输入正确的实验状态：ENABLE / DISABLE");
                }
                if (!checkDateTime(experimentParam.getStartTime()) || ! checkDateTime(experimentParam.getEndTime())){
                    throw new IllegalArgumentException("请输入正确的实验时间格式： 2020-01-01 24:00:00");
                }

                /*if(userId.equals(experiment.getCreatorId())){
                    Experiment experiment1 = experimentMapper.experimentParamExperiment(experimentParam);
                    experimentRepository.updateById(experiment1);

                    List<Integer> newRequiredProblems = removeProblems(experimentParam,"REQUIRED");
                    List<Integer> newOptionalProblems = removeProblems(experimentParam,"OPTIONAL");
                    //删除完共同题目之后那么newProblems中剩下的就是新题目了
                    if (newOptionalProblems.size() != 0){
                        doProblemRelatedExperiment(newOptionalProblems, "OPTIONAL",experiment1);
                    }
                    if (newRequiredProblems.size() != 0){
                        doProblemRelatedExperiment(newRequiredProblems, "REQUIRED",experiment1);
                    }
                    return (T) findById(experimentParam.getId());
                }else {

                }*/
                ExperimentUploadDto experimentUploadDto = experimentMapper.paramToDto(experimentParam);
                //更新之后继承原来实验的权重
                Integer weight = experimentSchoolRepository.selectWeightByExperimentIdAndSchoolId(userInfo.getSchoolId(), experimentUploadDto.getId());
                this.delete(experimentParam.getId(), userId);
                ExperimentBo bo = addExperiment(userId, experimentUploadDto);
                ExperimentSchool newExperimentSchool = experimentSchoolRepository.selectByExperimentIdAndSchoolId(userInfo.getSchoolId(), bo.getId());
                newExperimentSchool.setWeight(weight);
                experimentSchoolRepository.updateById(newExperimentSchool);
                ExperimentBo experimentBo = findByExperimentIdAndSchoolId(bo.getId(), userInfo.getSchoolId());
                experimentBo.setCreator(userService.findUsernameById(userId));
                experimentBo.setCreatorSchool(userService.findUserSchoolById(userId));
                return (T) experimentBo;
            }
        }
    }

    public List<Integer> removeProblems(ExperimentParam experimentParam, String category){
        //修改前该实验的所有问题
        List<Integer> newProblems = new ArrayList<>();
        //修改后该实验的所有问题
        List<Integer> oldProblems = experimentProblemRepository.listProblemIdsByExperimentId(experimentParam.getId(), category);
        List<Integer> temp = new ArrayList<Integer>();
        if ("OPTIONAL".equals(category)){
            newProblems = experimentParam.getOptionalQuestions();
        }else if ("REQUIRED".equals(category)){
            newProblems = experimentParam.getRequiredQuestions();
        }
        for (Integer oldProblem:oldProblems){
            if (oldProblem != null) {
                boolean exist = problemService.exist(oldProblem);
                if (exist) {
                    //若旧题目在新题目组中不存在
                    if (!newProblems.contains(oldProblem)) {
                        //删除关联表中的信息
                        Map map = new HashMap();
                        map.put("experiment_id",experimentParam.getId());
                        map.put("problem_id",oldProblem);
                        experimentProblemRepository.deleteByMap(map);
                        //oldProblems.remove(oldProblem);
                    }else {
                        temp.add(oldProblem);
                    }
                }else {
                    experimentProblemRepository.deleteById(experimentProblemRepository.findIdByExperimentIdAndProblemId(experimentParam.getId(), oldProblem));
                }
            }
        }

        //此时temp中的值为新题目组和旧题目组的共同题目
        //将共同题目在newProblems中删除
        newProblems.removeAll(temp);
        return newProblems;
    }

    @Override
    public Boolean delete(Integer experimentId,Integer userId) {
        Experiment experiment = experimentRepository.selectById(experimentId);
        if (experiment == null) {
            throw new ResourceExistException(String.format("当前实验不存在"));
        }
        Map hashMap = new HashMap();
        hashMap.put("experiment_id",experimentId);
        if (experimentResultRepository.selectByMap(hashMap).size() > 0){
            throw new ResourceExistException(String.format("该实验已经有成绩，您无法删除"));
        }
        String role = userService.getUserRolesByUserId(userId);
        if (!"schoolAdmin".equals(role) && !"superAdmin".equals(role) && !"teacher".equals(role)){
            throw new ResourceExistException(String.format("您不是管理员，无权删除实验"));
        }else {
            UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
            Map map = new HashMap();
            map.put("experiment_id",experimentId);
            map.put("school_id",userInfo.getSchoolId());
            //超级管理员或者题目创建人才可以把实验完整的删除，包括实验的基本信息，否则只能删除与本校关联的实验信息
            //该校管理员也可以删除本校教师创建的题目

            //该实验创建人的学校id，如果该id与本校管理员的学校一致
            Integer createSchoolId = userInfoRepository.getUserInfoByUserId(experiment.getCreatorId()).getSchoolId();
            if ("superAdmin".equals(role)|| ("schoolAdmin".equals(role) && Objects.equals(createSchoolId,userInfo.getSchoolId())) || Objects.equals(userId, experiment.getCreatorId())){
                map.remove("school_id");
                experimentSchoolRepository.deleteByMap(map);
                if (experimentProblemRepository.findProblemIdsByExperimentId(experimentId).size() != 0){
                    experimentProblemRepository.deleteExperimentProblemByExperimentId(experimentId);
                }
                return experimentRepository.deleteById(experimentId) > 0 ;
            }else {
                int flag = experimentSchoolRepository.deleteByMap(map);
                return flag > 0 ? true : false;
            }
        }
    }

    @Override
    public ExperimentVo addExperiment(@Valid ExperimentUploadParam experimentUploadParam) {
        Experiment from = experimentMapper.uploadParamToDo(experimentUploadParam);
        experimentRepository.insert(from);
        doProblemRelatedExperiment(experimentUploadParam.getOptionalQuestions(), "OPTIONAL",from);
        doProblemRelatedExperiment(experimentUploadParam.getRequiredQuestions(), "REQUIRED",from);
        return findById(from.getId());
    }

    @Override
    public ExperimentBo addExperiment(Integer userId, ExperimentUploadDto experiment) {
        String role = userService.getUserRolesByUserId(userId);
        //System.out.println(role);
        if (!"schoolAdmin".equals(role) && !"superAdmin".equals(role) && !"teacher".equals(role)){
            throw new ResourceExistException(String.format("您无权创建实验"));
        }
        if (!"ENABLE".equals(experiment.getStatus()) && !"DISABLE".equals(experiment.getStatus())){
            throw new IllegalArgumentException("请输入正确的实验状态：ENABLE / DISABLE");
        }
        if (!checkDateTime(experiment.getStartTime()) || ! checkDateTime(experiment.getEndTime())){
            throw new IllegalArgumentException("请输入正确的实验时间格式： 2020-01-01 12:00:00");
        }
        UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
        Experiment from = experimentMapper.experimentUploadDtoToExperiment(experiment);
        from.setCreatorId(userId);
        experimentRepository.insert(from);
        String username = userService.findUsernameById(userId);
        if ("schoolAdmin".equals(role) || "teacher".equals(role)){
            doExperimentRelatedAll(from,
                    DateTimeUtils.toDateStr(experiment.getStartTime()),
                    DateTimeUtils.toDateStr(experiment.getEndTime()),
                    experiment.getStatus(),
                    userInfo.getSchoolId());

            doProblemRelatedExperiment(experiment.getOptionalQuestions(), "OPTIONAL",from);
            doProblemRelatedExperiment(experiment.getRequiredQuestions(), "REQUIRED",from);
            ExperimentBo experimentBo = findByExperimentIdAndSchoolId(from.getId(), userInfo.getSchoolId());
            experimentBo.setCreator(username);
            experimentBo.setCreatorSchool(userService.findUserSchoolById(userId));
            return experimentBo;
        }else {
            doExperimentRelatedAll(from,
                    DateTimeUtils.toDateStr(experiment.getStartTime()),
                    DateTimeUtils.toDateStr(experiment.getEndTime()),
                    experiment.getStatus(),
                    experiment.getSchool());
            doProblemRelatedExperiment(experiment.getOptionalQuestions(), "OPTIONAL",from);
            doProblemRelatedExperiment(experiment.getRequiredQuestions(), "REQUIRED",from);
            ExperimentBo experimentBo = findByExperimentIdAndSchoolId(from.getId(), experiment.getSchool());
            experimentBo.setCreator(username);
            experimentBo.setCreatorSchool(schoolService.findSchoolById(experiment.getSchool()).getSchoolName());
            return experimentBo;
        }
    }

    /**
     * 将时间、状态、学校和实验进行一个关联
     */
    private void doExperimentRelatedAll(Experiment experiment, LocalDateTime startTime,LocalDateTime endTime, String status, Integer school) {
        if (ObjectUtils.isEmpty(experiment)) {
            return;
        }
        if (!schoolService.exist(school)){
            throw new ResourceNotFoundException(String.format("没有这个学校，请输入已有的学校ID"));
        }
        //List<ExperimentProblem> experimentProblems = new ArrayList<>();{
        ExperimentSchool experimentSchool = new ExperimentSchool();
        experimentSchool.setExperimentId(experiment.getId());
        experimentSchool.setStatus(status);
        experimentSchool.setStartTime(startTime);
        experimentSchool.setEndTime(endTime);
        experimentSchool.setSchoolId(school);
        experimentSchoolRepository.insert(experimentSchool);
    }

    /**
     * 将状态和实验进行一个关联
     */
    private void doExperimentRelatedStatus(Experiment experiment, String status) {
        if (ObjectUtils.isEmpty(experiment)) {
            return;
        }
        //List<ExperimentProblem> experimentProblems = new ArrayList<>();{
        ExperimentSchool experimentSchool = new ExperimentSchool();
        experimentSchool.setExperimentId(experiment.getId());
        experimentSchool.setStatus(status);
        experimentSchoolRepository.insert(experimentSchool);
    }

    /**
     * 将时间和实验进行一个关联
     */
    private void doExperimentRelatedTime(Experiment experiment, LocalDateTime startTime,LocalDateTime endTime) {
        if (ObjectUtils.isEmpty(experiment)) {
            return;
        }
        //List<ExperimentProblem> experimentProblems = new ArrayList<>();{
        ExperimentSchool experimentSchool = new ExperimentSchool();
        experimentSchool.setExperimentId(experiment.getId());
        experimentSchool.setStartTime(startTime);
        experimentSchool.setEndTime(endTime);
        experimentSchoolRepository.insert(experimentSchool);
    }

    @Override
    public boolean doExperimentRelatedSchool(Integer experimentId, Integer schoolId) {
        if (!schoolService.exist(schoolId)){
            throw new ResourceNotFoundException(String.format("没有这个学校，请输入已有的学校ID"));
        }
        Experiment experiment = experimentRepository.selectById(experimentId);
        boolean relatedSchool = doExperimentRelatedSchool(experiment, schoolId);
        if (relatedSchool){
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
            Calendar curr = Calendar.getInstance();
            String startTime = df.format(curr.getTime());
            curr.set(Calendar.YEAR,curr.get(Calendar.YEAR)+1);
            String endTime = df.format(curr.getTime());
            setExperimentTime(experimentId, schoolId, startTime, endTime);
        }
        return relatedSchool;
    }

    @Override
    public boolean updateProblemCategory(Integer experimentId, Integer schoolId, Integer problemId) {
        List<Integer> relatedSchoolIds = experimentSchoolRepository.findSchoolIdsByExperimentId(experimentId);
        if (!relatedSchoolIds.contains(schoolId)){
            throw new ResourceNotFoundException(String.format("该实验没有与输入的学校关联，请先将该实验与该学校关联"));
        }
        Integer experimentProblemId = experimentProblemRepository.findIdByExperimentIdAndProblemId(experimentId, problemId);
        ExperimentProblem experimentProblem = experimentProblemRepository.selectById(experimentProblemId);
        String updatedSchoolIds = experimentProblem.getUpdatedSchoolIds();
        //防止数据库中的updated_school_ids字段为null
        if (updatedSchoolIds == null){
            updatedSchoolIds = "[]";
        }
        List<Integer> updatedSchoolIdList = conversion(updatedSchoolIds);
        //防止数据库中的updated_school_ids字段为空
        if (updatedSchoolIdList == null){
            updatedSchoolIdList = new ArrayList<>();
        }

        if (updatedSchoolIdList.contains(schoolId)){
            updatedSchoolIdList.remove(schoolId);
        }else {
            updatedSchoolIdList.add(schoolId);
        }
        updatedSchoolIds = toJsonStr(updatedSchoolIdList);
        experimentProblem.setUpdatedSchoolIds(updatedSchoolIds);
        if (experimentProblemRepository.updateById(experimentProblem) > 0){
            return true;
        }
        return false;
    }

    public static List<Integer> conversion(String str){
        List<Integer> updatedSchoolIds = JSON.parseArray(str, Integer.class);
        return updatedSchoolIds;
    }
    public static String toJsonStr(List<Integer> updatedSchoolIds){
        return JSONUtil.toJsonStr(updatedSchoolIds);
    }

    /**
     * 将学校和实验进行一个关联
     */
    private boolean doExperimentRelatedSchool(Experiment experiment, Integer school) {
        if (ObjectUtils.isEmpty(experiment)) {
            return false;
        }
        Integer experimentId = experimentSchoolRepository.findIdBySchoolIdAndExperimentId(school, experiment.getId());
        System.out.println(experimentId);
        if (experimentId == null){
            //List<ExperimentProblem> experimentProblems = new ArrayList<>();{
            ExperimentSchool experimentSchool = new ExperimentSchool();
            experimentSchool.setExperimentId(experiment.getId());
            experimentSchool.setSchoolId(school);
            if (experimentSchoolRepository.insert(experimentSchool) > 0){
                return true;
            }
        }else {
            throw new ResourceNotFoundException(String.format("该学校已关联该实验"));
        }

        return false;
    }

    /**
     * 将题目和实验进行一个关联
     */
    private void doProblemRelatedExperiment(List<Integer> problemBos, String category,Experiment experiment) {
        if (ObjectUtils.isEmpty(problemBos)) {
            return;
        }
        //List<ExperimentProblem> experimentProblems = new ArrayList<>();
        for (Integer problem : problemBos) {
            if (problemService.exist(problem)){
                ExperimentProblem experimentProblem = new ExperimentProblem();
                experimentProblem.setProblemId(problem);
                experimentProblem.setExperimentId(experiment.getId());
                experimentProblem.setCategory(category);
                experimentProblemRepository.insert(experimentProblem);
            }else {
                throw new IllegalArgumentException(String.format("The problem [%d] does not exist", problem));
            }

            //experimentProblems.add(experimentProblem);
        }
        //experimentProblemRepository.insertAll(experimentProblems);
    }



    @Override
    public List<ExperimentBo> listBySchoolId(Integer schoolId,Integer userId, String status, Integer pageNum, Integer pageSize) {


        //QueryWrapper<Experiment> wrapper = new QueryWrapper<>();
        /*Map map=new HashMap();
        map.put("school_id", schoolId);
        map.put("status",status);*/
        List<ExperimentBo> experimentBoList = experimentSchoolRepository.findExperimentBySchoolIdAndStatus(schoolId, status, pageNum, pageSize);

        if (!CollectionUtils.isEmpty(experimentBoList)){
            for (ExperimentBo experimentBo:experimentBoList){
                /*List<Integer> problemIdsByExperimentId = experimentProblemRepository.findProblemIdsByExperimentId(experimentBo.getId());
                experimentBo.setQuestions(problemService.listByIds(problemIdsByExperimentId));*/
                /*List<ProblemParam> optionalProblems = findProblemBySchoolId(experimentBo.getId(), schoolId, "OPTIONAL");
                List<ProblemParam> requiredProblems = findProblemBySchoolId(experimentBo.getId(), schoolId, "REQUIRED");*/

                /*List<ProblemParam> optionalProblems = findProblemByExperimentId(experimentBo.getId(),  "OPTIONAL");
                List<ProblemParam> requiredProblems = findProblemByExperimentId(experimentBo.getId(),  "REQUIRED");
                experimentBo.setOptionalQuestions(optionalProblems);
                experimentBo.setRequiredQuestions(requiredProblems);*/

                experimentBo.setLimitDateTime(experimentBo.getStartTime(),experimentBo.getEndTime());
                //experimentBo.setSchoolId(schoolId);

            }
            return experimentBoList;
        } else {
            throw new ResourceNotFoundException(String.format("The pageNum [%d] does not exist.", pageNum));
        }
    }

    @Override
    public List<ExperimentBo> listByClassId(Integer classId,  Integer schoolId, String status, Integer pageNum, Integer pageSize) {
        /**
        * @Description:因为现在需求没有和班级关联，所以以下代码暂时用不着
        * @Param: [classId, schoolId, pageNum, pageSize]
        * @Param: [classId, schoolId, pageNum, pageSize]
        * @return: java.util.List<com.masonluo.mlonlinejudge.model.bo.ExperimentBo>
        * @Author: LOTP
        * @Date: 2021/10/26
        */

        /*IPage<Experiment> page = new Page<>(pageNum, pageSize);
        //QueryWrapper<Experiment> wrapper = new QueryWrapper<>();
        Map map=new HashMap();
        map.put("school_id", schoolId);
        map.put("class_id", classId);
        IPage<Experiment> experimentIPage = experimentClassRepository.findExperimentByClassId(page,map);
        if (!CollectionUtils.isEmpty(experimentIPage.getRecords())){
            List<ExperimentBo> experiments = new ArrayList<>();
            experiments = (List<ExperimentBo>) page.getRecords().stream().map(experiment -> {
                return experimentMapper.doToBo(experiment);
            }).collect(Collectors.toList());
            for (ExperimentBo experimentBo:experiments){
                experimentBo.setLimitDateTime(experimentBo.getStartTime(),experimentBo.getEndTime());
                List<Integer> problemIdsByExperimentId = experimentProblemRepository.findProblemIdsByExperimentId(experimentBo.getId());
                experimentBo.setQuestions(problemService.listByIds(problemIdsByExperimentId));
            }
            return experiments;
        } else {
            throw new ResourceNotFoundException(String.format("The schoolId [%d] or classId [%d] does not exist.", schoolId,classId));
        }*/
        //return listBySchoolId(schoolId,status,pageNum,pageSize);
        throw new IllegalArgumentException("该接口已不使用");
    }

    @Override
    public boolean setExperimentStatus(Integer experimentId, Integer schoolId, String status) {
        Integer experimentSchoolId = experimentSchoolRepository.findIdBySchoolIdAndExperimentId(schoolId, experimentId);
        if(experimentSchoolId != null && experimentSchoolId > 0){
            ExperimentSchool experimentSchool = new ExperimentSchool();
            experimentSchool.setId(experimentSchoolId);
            experimentSchool.setStatus(status);
            experimentSchoolRepository.updateById(experimentSchool);
            return true;
        }else {
            throw new ResourceNotFoundException(String.format("该实验没有与输入的学校关联，请先将该实验与该学校关联"));
        }
    }

    @Override
    public boolean setExperimentTime(Integer experimentId, Integer schoolId, String startTime, String endTime) {
        if (!checkDateTime(startTime) || ! checkDateTime(endTime)){
            throw new IllegalArgumentException("请输入正确的实验时间格式： 2020-01-01 12:00:00");
        }
        Integer experimentSchoolId = experimentSchoolRepository.findIdBySchoolIdAndExperimentId(schoolId, experimentId);
        if(experimentSchoolId != null && experimentSchoolId > 0){
            ExperimentSchool experimentSchool = new ExperimentSchool();
            experimentSchool.setId(experimentSchoolId);
            experimentSchool.setStartTime(DateTimeUtils.toDateStr(startTime));
            experimentSchool.setEndTime(DateTimeUtils.toDateStr(endTime));
            return experimentSchoolRepository.updateById(experimentSchool) > 0;
        }else {
            throw new ResourceNotFoundException(String.format("该实验没有与输入的学校关联，请先将该实验与该学校关联"));
        }
    }

    @Override
    public List<ExperimentVo> findNotRelatedSchool(Integer userId,Integer pageNum, Integer pageSize) {
        UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
        List<Experiment> notRelatedSchools = experimentRepository.findNotRelatedSchool(userInfo.getSchoolId(),pageNum,pageSize);
        List<ExperimentVo> experimentVos = experimentMapper.doToVo(notRelatedSchools);
        experimentVos.forEach(experimentVo -> {
            int creatorId = Integer.parseInt(experimentVo.getCreator());
            experimentVo.setCreator(userService.findUsernameById(creatorId));
            experimentVo.setCreatorSchool(userService.findUserSchoolById(creatorId));

        });
        return experimentVos;
    }

    @Override
    public int countNotRelatedSchool(Integer userId) {
        UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
        return experimentRepository.countNotRelatedSchool(userInfo.getSchoolId());
    }

    @Override
    public List<ProblemParam> findProblemBySchoolId(Integer experimentId, Integer schoolId, String category) {
        List<Problem> notUpdatedProblems = experimentProblemRepository.findNotUpdatedProblems(experimentId, schoolId, category);
        List<Problem> updatedProblems = new ArrayList<>();
        if ("OPTIONAL".equals(category)){
            updatedProblems = experimentProblemRepository.findUpdatedProblems(experimentId, schoolId, "REQUIRED");
        }else if ("REQUIRED".equals(category)){
            updatedProblems = experimentProblemRepository.findUpdatedProblems(experimentId, schoolId, "OPTIONAL");
        }else {
            throw new ResourceNotFoundException(String.format("请输入正确的分类：REQUIRED/OPTIONAL"));
        }
        notUpdatedProblems.addAll(updatedProblems);
        List<ProblemParam> problemParams = problemMapper.doToParam(notUpdatedProblems);
        problemParams.forEach(problemParam -> {
            problemParam.setTags(problemService.findTagVoByProblemId(problemParam.getId()));
            problemParam.setIoSamples(ioSampleService.findByProblemId(problemParam.getId()));
        });
        return problemParams;
    }

    @Override
    public int countAll() {
        return experimentRepository.countAll();
    }

    @Override
    public int countByAdmin() {
        return experimentRepository.countByAdmin();
    }

    @Override
    public int countBySchoolId(Integer schoolId, String status) {
        return experimentRepository.countBySchoolId(schoolId,status);
    }

    @Override
    public int countByUserId(Integer userId,String status) {
        int count = 0;
        if (Objects.isNull(userId)){
            count =countAll();
        }else {
            String role = userService.getUserRolesByUserId(userId);
            UserInfo userInfo=userInfoRepository.getUserInfoByUserId(userId);
            if ("superAdmin".equals(role)){
                //count = countByAdmin();
                count = countAll();
            }else if ("schoolAdmin".equals(role)){
                count = countBySchoolId(userInfo.getSchoolId(),status);
            }else if ("teacher".equals(role)){
                count = countBySchoolId(userInfo.getSchoolId(),status);
            }else if ("student".equals(role)){
                count = countBySchoolId(userInfo.getSchoolId(),status);
            }
        }
        return count;
    }

    @Override
    public int countByClassIdAndSchoolId(Integer classId, Integer schoolId) {
        return experimentRepository.countByClassIdAndSchoolId(classId, schoolId);
    }

    @Override
    public String findNameByExperimentId(Integer id) {
        return experimentRepository.findNameByExperimentId(id);
    }

    public Boolean checkDateTime(String time){
        String regex="^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1][0-9])|([2][0-4]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$";
        boolean match=time.matches(regex);
        if(match) {
            return true;
        }
        else {
            return false;
        }
    }

    @Override
    public boolean sortExperimentByIdsAndSchoolId(List<Integer> experimentIds, Integer schoolId){
        //1.根据实验ids和学校id在t_experiment_school_class表里确定是哪些实验,按照experimentIds中的顺序返回List<ExperimenSchool> experimenSchool
        List<ExperimentSchool> newExperimentSchools = new ArrayList<>();
        experimentIds.forEach(experimentId->{
            ExperimentSchool experimentSchool = experimentSchoolRepository.selectByExperimentIdAndSchoolId(schoolId, experimentId);
            newExperimentSchools.add(experimentSchool);
        });


        //2.根据实验ids和学校id在t_experiment_school_class表里确定是哪些实验,按照权重返回List<ExperimenSchool> experimenSchool
        List<ExperimentSchool> oldExperimentSchools = experimentSchoolRepository.selectByExperimentIdsAndSchoolId(schoolId, experimentIds, true);

        //3.遍历实验列表，直接让newExperimentSchools中的每一个newExperimentSchool的权重等于对应旧实验列表的权重
        for(int i = 0; i < newExperimentSchools.size(); i++){
            //旧实验列表是按照权重从小到大排序的，所以它的权重就是即将要赋予新实验列表对应index的新的权重值
            int newWeight = oldExperimentSchools.get(i).getWeight();
            //而新实验列表是按照前端传回的新排序，所以它的权重就是旧的权重值
            int oldWeight = newExperimentSchools.get(i).getWeight();
            //权重值不相等才需要修改，并进行更新
            if (newWeight != oldWeight){
                newExperimentSchools.get(i).setWeight(newWeight);
                int update = experimentSchoolRepository.updateById(newExperimentSchools.get(i));
                if (update < 0){
                    throw new ResourceNotFoundException(String.format("修改失败"));
                }
            }
        }
        return true;

    }








}


